package seguridad;

import java.io.*;
import java.security.Key;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.spec.AlgorithmParameterSpec;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DesEncrypter
{
    Cipher ecipher;
    Cipher dcipher;

    DesEncrypter( SecretKey key )
    {
        // Create an 8-byte initialization vector
        byte[] iv = new byte[]{ ( byte )0x8E, 0x12, 0x39, ( byte )0x9C, 0x07, 0x72, 0x6F, 0x5A };
        // byte[] iv = new byte[]{ ( byte )0x8E, 0x12, 0x39, ( byte )0x9C};
        
       
        AlgorithmParameterSpec paramSpec = new IvParameterSpec( iv );
        try
        {
//            ecipher = Cipher.getInstance( "DES/CBC/PKCS5Padding" );
//            dcipher = Cipher.getInstance( "DES/CBC/PKCS5Padding" );

            ecipher = Cipher.getInstance( key.getAlgorithm() );
            dcipher = Cipher.getInstance( key.getAlgorithm() );
            
            // CBC requires an initialization vector
            ecipher.init( Cipher.ENCRYPT_MODE, key, paramSpec );
            dcipher.init( Cipher.DECRYPT_MODE, key, paramSpec );
        }
        catch( java.security.InvalidAlgorithmParameterException e )
        {
        }
        catch( javax.crypto.NoSuchPaddingException e )
        {
        }
        catch( java.security.NoSuchAlgorithmException e )
        {
        }
        catch( java.security.InvalidKeyException e )
        {
        }
    }

    // Buffer used to transport the bytes from one stream to another
    byte[] buf = new byte[1024];

    public void encrypt( InputStream in, OutputStream out )
    {
        try
        {
            // Bytes written to out will be encrypted
            out = new CipherOutputStream( out, ecipher );

            // Read in the cleartext bytes and write to out to encrypt
            int numRead = 0;
            while( ( numRead = in.read( buf ) ) >= 0 )
            {
                out.write( buf, 0, numRead );
            }
            out.close( );
        }
        catch( java.io.IOException e )
        {
        }
    }

    public void decrypt( InputStream in, OutputStream out )
    {
        try
        {
            // Bytes read from in will be decrypted
            in = new CipherInputStream( in, dcipher );

            // Read in the decrypted bytes and write the cleartext to out
            int numRead = 0;
            while( ( numRead = in.read( buf ) ) >= 0 )
            {
                out.write( buf, 0, numRead );
            }
            out.close( );
        }
        catch( java.io.IOException e )
        {
        }
    }
     private static byte[] getMD5(String input){
        try{
            byte[] bytesOfMessage = input.getBytes("UTF-8");
            MessageDigest md = MessageDigest.getInstance("MD5");
            return md.digest(bytesOfMessage);
        }  catch (Exception e){
             return null;
        }
    }
    public static void cifrarArchivo( String ruta, String contrasenia )
    {
        try
        {   
            byte[] salt = "salt1234".getBytes();
            PBEParameterSpec paraSpec = new PBEParameterSpec(salt,20);
            PBEKeySpec keySpec = new PBEKeySpec(contrasenia.toCharArray());
            SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            //SecretKey key = kf.generateSecret(keySpec);
            // Generate a temporary key. In practice, you would save this key.
            // See also Encrypting with DES Using a Pass Phrase.
            //SecretKey key = KeyGenerator.getInstance( "DES" ).generateKey( );

            SecretKeySpec skey = new SecretKeySpec(getMD5(contrasenia), "AES");
            
            // Create encrypter/decrypter class
            DesEncrypter encrypter = new DesEncrypter( skey );

            File archivoClaro = new File(ruta);
            File archivoCifrado = new File(ruta+".cifrado");
            File archivoClaro2 = new File(ruta+".descifrado");
            // Encrypt
            System.out.println("Voy a cifrar!!!!");
            encrypter.encrypt( new FileInputStream(archivoClaro), new FileOutputStream( archivoCifrado) );
            System.out.println("Ya lo cifre!!!!");

            // Decrypt
            encrypter.decrypt( new FileInputStream(archivoCifrado), new FileOutputStream( archivoClaro2 ) );
        }
        catch( Exception e )
        {
            e.printStackTrace();
        }
    }
    
     public static void cifrarArchivoConPrivada( String ruta, String contrasenia, KeyPair kp )
    {
        try
        {   
            byte[] salt = "salt1234".getBytes();
            PBEParameterSpec paraSpec = new PBEParameterSpec(salt,20);
            PBEKeySpec keySpec = new PBEKeySpec(contrasenia.toCharArray());
            SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
            SecretKey key = kf.generateSecret(keySpec);
            // Generate a temporary key. In practice, you would save this key.
            // See also Encrypting with DES Using a Pass Phrase.
            //SecretKey key = kf.translateKey(kp.getPrivate());
            
           // SecretKey key = KeyGenerator.getInstance("RSA");
           
            // Create encrypter/decrypter class
            DesEncrypter encrypter = new DesEncrypter( key );

            File archivoClaro = new File(ruta);
            File archivoCifrado = new File(ruta+".cifrado");
            File archivoClaro2 = new File(ruta+".descifrado");
            // Encrypt
            System.out.println("Voy a cifrar!!!!");
            encrypter.encrypt( new FileInputStream(archivoClaro), new FileOutputStream( archivoCifrado) );
            System.out.println("Ya lo cifre!!!!");

            System.out.println("Voy a descifrar!!!!");
            // Decrypt
            encrypter.decrypt( new FileInputStream(archivoCifrado), new FileOutputStream( archivoClaro2 ) );
            System.out.println("Ya lo cifre!!!!");
        }
        catch( Exception e )
        {
        }
    }
    
    public static void main( String[] args )
    {
        try 
        {
            BufferedReader stdIn = new BufferedReader( new InputStreamReader( System.in ) );
            String contrasenia = stdIn.readLine( );
            DesEncrypter.cifrarArchivo( "./data/cleartext1", contrasenia );
        } catch (IOException ex)
        {
            Logger.getLogger(DesEncrypter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
